package com.net.xpay.core.service.impl;

import com.alipay.api.AlipayApiException;
import com.alipay.api.response.AlipayFundBatchCreateResponse;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.net.xpay.common.domain.User;
import com.net.xpay.core.constant.CoreConstant;
import com.net.xpay.core.constant.PoseidonErrorCode;
import com.net.xpay.core.domain.*;
import com.net.xpay.core.manager.*;
import com.net.common.annotation.WriteTransactional;
import com.net.common.exception.BusinessException;
import com.net.common.util.SerializationUtil;
import com.net.xpay.alipay.AlipayProperties;
import com.net.xpay.alipay.PoseidonAlipayClient;
import com.net.xpay.alipay.model.TransOrderModel;
import com.net.xpay.core.domain.*;
import com.net.xpay.core.enums.AccountBillType;
import com.net.xpay.core.enums.AlipayUserStatus;
import com.net.xpay.core.enums.PayTransBatchStatus;
import com.net.xpay.core.enums.PayTransStatus;
import com.net.xpay.core.helper.AccountDetailHelper;
import com.net.xpay.core.manager.*;
import com.net.xpay.core.service.AccountService;
import com.net.xpay.core.service.OtherPayTransBatchService;
import com.net.xpay.core.utils.GsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;

/**
 * 2020/10/26 19:07

 */
@Slf4j
@Service
@WriteTransactional
public class OtherPayTransBatchServiceImpl implements OtherPayTransBatchService {

    @Autowired
    private PayTransBatchManager payTransBatchManager;

    @Autowired
    private PoseidonAlipayClient xpayAlipayClient;

    @Autowired
    private AlipayUserManager alipayUserManager;

    @Autowired
    private PayTransSummaryManager payTransSummaryManager;

    @Autowired
    private PayTransRecordManager payTransRecordManager;

    @Autowired
    private PayTransManager payTransManager;

    @Autowired
    private AlipayProperties alipayProperties;

    @Autowired
    private UserAccountManager userAccountManager;

    @Autowired
    private AccountService accountService;

    @Autowired
    private AccountDetailHelper accountDetailHelper;


    /**
     * 代付批次打款 渠道用户替渠道发起实际的转账
     */
    @Override
    public String otherPayBatchPayTrans(User masterUser, User slaveUser, Long id, String alipayNickName, String returnUrl) {
        Preconditions.checkArgument(id != null);
        PayTransBatch payTransBatch = payTransBatchManager.findById(masterUser.getId(), id);
        if (payTransBatch == null) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "打款批次不存在");
        }
        if (!Boolean.TRUE.equals(payTransBatch.getOtherTrans())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "此批次不是代转批次");
        }
        if (!Objects.equals(payTransBatch.getExecuteUserId(), slaveUser.getId())) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "渠道转账用户不匹配");
        }

        if (payTransBatch.getStatus() != PayTransBatchStatus.IMPORTED && payTransBatch.getStatus() != PayTransBatchStatus.DISUSE) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "当前打款批次已处理，请勿重复操作");
        }

        AlipayUser alipayUser;
        if (!Strings.isNullOrEmpty(alipayNickName)) {
            alipayUser = alipayUserManager.findByAlipayNickName(slaveUser.getId(), alipayNickName);
            if (alipayUser == null) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "付款方支付宝账号不存在");
            }
        } else {
            if (slaveUser.getAlipayUserId() == null) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请先绑定支付宝账号");
            }
            alipayUser = alipayUserManager.getById(slaveUser.getAlipayUserId());
        }

        if (alipayUser == null || alipayUser.getStatus() != AlipayUserStatus.YES) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "你的支付宝账号尚未签约，请先签约后再打款");
        }

//        if (alipayUser.getExpiresIn().isBefore(LocalDateTime.now())) {
//            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "支付宝账号签约已过期，请重新签约");
//        }

        UserAccount userAccount = userAccountManager.getByIdWithLock(masterUser.getId());
        //有剩余的批次次数
        checkHasLeftTransBatch(userAccount, payTransBatch);

        //记录此次发起的批次交易记录
        PayTransSummary payTransSummary = createOtherPayTransSummary(masterUser, slaveUser, alipayUser, payTransBatch);
        List<PayTransRecord> payTransRecords = createOtherPayTransRecords(payTransSummary);

        //创建支付宝批量打款订单
        alipayFundBatchCreate(payTransSummary, payTransRecords, alipayUser);

       try {
            String payUrl = xpayAlipayClient.alipayFundTransPagePay(alipayUser.getAuthToken(), payTransSummary.getBatchTransId(), returnUrl);
            payTransBatch.setStatus(PayTransBatchStatus.WAIT_PAY);
            payTransBatch.setLastPayUrl(payUrl);
            payTransBatch.setBatchTransId(payTransSummary.getBatchTransId());
            payTransBatchManager.updateByPrimaryKeyWithVersion(payTransBatch);
            payTransManager.updateStatusByPayTransBatchId(masterUser.getId(), payTransBatch.getId(), PayTransStatus.WAIT_PAY, payTransBatch.getFree(), null);
            payTransSummary.setStatus(PayTransBatchStatus.WAIT_PAY);
            payTransSummaryManager.updateByPrimaryKeyWithVersion(payTransSummary);

            payServiceMoney(masterUser, userAccount, payTransBatch);
            return payUrl;
        } catch (AlipayApiException e) {
            log.warn("batchPayTrans error|userId={}|id={}", id, e);
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, e.getErrMsg());
        }
    }

    private void checkHasLeftTransBatch(UserAccount userAccount, PayTransBatch payTransBatch) {
        if (userAccount.getTransBatchLeft() > 0L && new BigDecimal(payTransBatch.getTotalTransAmount()).compareTo(CoreConstant.MAX_TRANS_FREE_AMOUNT) <= 0) {
            payTransBatch.setFree(true);
            payTransBatch.setServiceRealPrice(0L);
            payTransBatch.setServicePrice(0L);
            payTransBatch.setServiceUnitPrice(0L);
            payTransBatchManager.updateByPrimaryKeyWithVersion(payTransBatch);
        }
    }

    private void payServiceMoney(User user, UserAccount userAccount, PayTransBatch payTransBatch) {
        if (payTransBatch.getFree()) {
            log.info("payServiceMoney but batch is free|batchId={}", payTransBatch.getId());
            //扣除免费次数
            AccountDetail accountDetail = AccountDetail.getInstance(user.getId(), payTransBatch.getLastSummaryId());
            accountDetailHelper.initTransBatchAccountDetail(accountDetail, AccountBillType.PAY_TRANS_SERVICE_PRICE, -1L, "批量转账扣除批次次数");
            accountService.onPay(user, userAccount, accountDetail);
            return;
        }
        AccountDetail accountDetail = AccountDetail.getInstance(user.getId(), payTransBatch.getLastSummaryId());
        accountDetailHelper.initCommonAccountDetail(accountDetail, AccountBillType.PAY_TRANS_SERVICE_PRICE, -payTransBatch.getServicePrice(), "批量转账扣除余额");

        accountService.onPay(user, userAccount, accountDetail);

        payTransBatch.setHasPayService(true);
        payTransBatchManager.updateByPrimaryKeyWithVersion(payTransBatch);
    }

    private void alipayFundBatchCreate(PayTransSummary payTransSummary, List<PayTransRecord> payTransRecords, AlipayUser alipayUser) {
        TransOrderModel transOrderModel = buildTransOrderModel(payTransSummary, payTransRecords);
        log.info("alipayFundBatchCreate params id={}|transOrderModel={}", payTransSummary.getPayTransBatchId(), GsonUtil.getGson().toJson(transOrderModel));
        AlipayFundBatchCreateResponse response;
        try {
            response = xpayAlipayClient.alipayFundBatchCreate(alipayUser.getAuthToken(), transOrderModel);
        } catch (AlipayApiException e) {
            log.warn("alipayFundBatchCreate error|id={}", payTransSummary.getPayTransBatchId(), e);
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "打款失败：" + e.getErrMsg());
        }
        log.info("alipayFundBatchCreate resp id={}|resp={}", payTransSummary.getPayTransBatchId(), SerializationUtil.obj2String(response));

        if (!response.isSuccess()) {
            log.warn("alipayFundBatchCreate failed userId={}|id={}|errorMsg={}", payTransSummary.getUserId(), payTransSummary.getPayTransBatchId(),  response.getSubMsg() + "|" + response.getMsg());
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "打款失败：" + response.getSubMsg() + "|" + response.getMsg());
        }

        payTransSummary.setBatchTransId(response.getBatchTransId());
        payTransSummary.setStatus(PayTransBatchStatus.of(response.getStatus()));
        payTransSummaryManager.updateByPrimaryKeyWithVersion(payTransSummary);

        for (PayTransRecord payTransRecord : payTransRecords) {
            payTransRecord.setBatchTransId(response.getBatchTransId());
        }

        payTransRecordManager.batchSave(payTransRecords);
    }

    private TransOrderModel buildTransOrderModel(PayTransSummary payTransSummary, List<PayTransRecord> payTransRecords) {
        TransOrderModel transOrderModel = TransOrderModel.getInstance();
        transOrderModel.setOutBatchNo(payTransSummary.getOutBatchNo());
        transOrderModel.setTotalTransAmount(payTransSummary.getTotalTransAmount());
        transOrderModel.setTotalCount(payTransSummary.getTotalCount().toString());
        transOrderModel.setProductCode(payTransSummary.getProductCode());
        transOrderModel.setBizScene(payTransSummary.getBizScene());
        transOrderModel.setOrderTitle(payTransSummary.getOrderTitle());
        transOrderModel.setTimeExpire(payTransSummary.getTimeExpire());
        transOrderModel.setRemark(payTransSummary.getRemark());
        List<TransOrderModel.TransOrderDetail> transOrderDetails = Lists.newArrayList();
        for (PayTransRecord record : payTransRecords) {
            TransOrderModel.TransOrderDetail detail = TransOrderModel.TransOrderDetail.getInstance();
            detail.setOutBizNo(record.getOutBizNo());
            detail.setTransAmount(record.getTransAmount());
            detail.setRemark(record.getRemark());

            TransOrderModel.PayeeInfo payeeInfo = TransOrderModel.PayeeInfo.getInstance();
            payeeInfo.setIdentity(record.getIdentity());
            payeeInfo.setIdentityType(record.getIdentityType());
            payeeInfo.setName(record.getName());

            detail.setPayeeInfo(payeeInfo);

            transOrderDetails.add(detail);
        }
        transOrderModel.setTransOrderList(transOrderDetails);
        return transOrderModel;
    }

    private List<PayTransRecord> createOtherPayTransRecords(PayTransSummary payTransSummary) {
        List<PayTrans> payTrans = payTransManager.listByPayTransBatchId(payTransSummary.getUserId(), payTransSummary.getPayTransBatchId());
        List<PayTransRecord> payTransRecords = Lists.newArrayList();
        for (PayTrans trans : payTrans) {
            trans.setAlipayUserId(payTransSummary.getAlipayUserId());
            trans.setAlipayNickName(payTransSummary.getAlipayNickName());

            PayTransRecord payTransRecord = PayTransRecord.getInstance();
            payTransRecord.setUserId(trans.getUserId());
            payTransRecord.setPartnerId(trans.getPartnerId());
            payTransRecord.setOtherTrans(true);
            payTransRecord.setExecuteUserId(payTransSummary.getExecuteUserId());
            payTransRecord.setExecuteMobile(payTransSummary.getExecuteMobile());
            payTransRecord.setExecuteOuterId(payTransSummary.getExecuteOuterId());
            payTransRecord.setMobile(trans.getMobile());
            payTransRecord.setAlipayUserId(payTransSummary.getAlipayUserId());
            payTransRecord.setAlipayNickName(payTransSummary.getAlipayNickName());
            payTransRecord.setPayTransId(trans.getId());
            payTransRecord.setBatchTransId(null);
            payTransRecord.setSummaryId(payTransSummary.getId());
            payTransRecord.setPayTransBatchId(trans.getPayTransBatchId());
            payTransRecord.setOutBatchNo(payTransSummary.getOutBatchNo());
            payTransRecord.setImportBatchNo(payTransSummary.getImportBatchNo());
            payTransRecord.setOutBizNo(trans.getOutBizNo());
            payTransRecord.setImportBizNo(trans.getImportBizNo());
            payTransRecord.setTransAmount(trans.getTransAmount());
            payTransRecord.setRemark(trans.getRemark());
            payTransRecord.setIdentity(trans.getIdentity());
            payTransRecord.setIdentityType(trans.getIdentityType());
            payTransRecord.setName(trans.getName());
            payTransRecord.setStatus(PayTransStatus.WAIT_PAY);
            payTransRecord.setVersion(0L);

            payTransRecords.add(payTransRecord);
        }

        //支付宝信息跟新一下
        payTransManager.batchUpdate(payTrans);
        return payTransRecords;
    }

    private PayTransSummary createOtherPayTransSummary(User masterUser, User slaveUser, AlipayUser alipayUser, PayTransBatch payTransBatch) {
        PayTransSummary payTransSummary = PayTransSummary.getInstance();
        payTransSummary.setUserId(payTransBatch.getUserId());
        payTransSummary.setPartnerId(payTransBatch.getPartnerId());
        payTransSummary.setOtherTrans(true);
        payTransSummary.setExecuteUserId(slaveUser.getId());
        payTransSummary.setExecuteMobile(slaveUser.getMobile());
        payTransSummary.setExecuteOuterId(slaveUser.getOuterId());
        payTransSummary.setAlipayUserId(alipayUser.getId());
        payTransSummary.setAlipayNickName(alipayUser.getAlipayNickName());
        payTransSummary.setMobile(masterUser.getMobile());
        payTransSummary.setOutBatchNo(null);
        payTransSummary.setBatchTransId(null);
        payTransSummary.setPayTransBatchId(payTransBatch.getId());
        payTransSummary.setImportBatchNo(payTransBatch.getImportBatchNo());
        payTransSummary.setServiceUnitPrice(payTransBatch.getServiceUnitPrice());
        payTransSummary.setServicePrice(payTransBatch.getServicePrice());
        payTransSummary.setTotalTransAmount(payTransBatch.getTotalTransAmount());
        payTransSummary.setTotalCount(payTransBatch.getTotalCount());
        payTransSummary.setSuccessAmount("0");
        payTransSummary.setSuccessCount(0L);
        payTransSummary.setFailedAmount("0");
        payTransSummary.setFailCount(0L);
        payTransSummary.setProductCode("BATCH_API_TO_ACC");
        payTransSummary.setBizScene("MESSAGE_BATCH_PAY");
        payTransSummary.setOrderTitle(payTransBatch.getOrderTitle());
        payTransSummary.setTimeExpire(payTransBatch.getTimeExpire());
        payTransSummary.setRemark(payTransBatch.getRemark());
        payTransSummary.setStatus(PayTransBatchStatus.IMPORTED);
        payTransSummary.setVersion(0L);

        payTransSummaryManager.save(payTransSummary);
        payTransBatch.setLastSummaryId(payTransSummary.getId());
        payTransBatch.setAlipayUserId(payTransSummary.getAlipayUserId());
        payTransBatch.setAlipayNickName(payTransSummary.getAlipayNickName());
        payTransBatchManager.updateByPrimaryKeyWithVersion(payTransBatch);
        return payTransSummary;
    }

}
